home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / perl / examples / gimp-make-img-map < prev    next >
Encoding:
Text File  |  2000-03-28  |  14.4 KB  |  453 lines

  1. #!/usr/local/bin/perl
  2.  
  3. # THIS IS OUTDATED AND WILL NOT RUN WITH CURRENT GIMP VERSIONS!
  4.  
  5. ######################################################################
  6. #  This program is an automatic way of scaling and tiling lots of
  7. #  images in order to create an index image.
  8. #
  9. #  Todo:
  10. #    - Add more layout algorithms. (fixed grid, dynamic grid, better
  11. #      orphan handling)
  12. #    - Add more decoration algorithms (e.g. negative strip, slides,
  13. #      sunken windows).
  14. #    - Create a way of supplying a template HTML index file into which
  15. #      the image map will be added.
  16. #    - Create a way of supplying a template HTML file in which
  17. #      full size images will be displayed. This file may include
  18. #      image annotations that come from the input file.
  19. #    - Define format of input file. This file should include
  20. #      annotations on/below images, comments in the full size html
  21. #      file, perhaps baloon text on top of images.
  22. #    - Make all parameters of tiling algorithms into options.
  23. #    - Change background of simple-shadow algorithm.
  24. #    - Option for either keeping image in gimp, or flattening and
  25. #      saving to disk.
  26. #    - Add a modular way of adding new layout and decoration algorithms.
  27. #
  28. #  Availability:
  29. #    - You can always find the latest version of this script at
  30. #      http://imagic.weizmann.ac.il/~dov/gimp/perl
  31. #
  32. #  Author:
  33. #    Dov Grobgeld <dov@imagic.weizmann.ac.il>
  34. #
  35. #  Bugs:
  36. #    -  -padx px means at least px and not exactly px. This should
  37. #       be fixed.
  38. #
  39. #  Version: 0.11
  40. ######################################################################
  41.  
  42. use Gimp;
  43.  
  44. # Defaults
  45. $max_height = 64;
  46. $layout_width = 600;
  47. $bgcolor = [194,194,194];
  48. $decoration = 'drop-shadow';
  49. $gutter_x = 15;
  50. $gutter_y = 15;
  51. $pad_x = 20;
  52. $pad_y = 20;
  53. chop($PWD = `pwd`);
  54.  
  55. # Routine for parsing the input format
  56. sub get_next_record {
  57.     return (undef,undef) if eof(IN);
  58.     local $_ = <IN>;
  59.     /^(\S+)\s+(.*)/;
  60.     return ($1,$2);
  61. }
  62.  
  63. # Load an image and return its id
  64. sub load_img {
  65.     my($fn) = shift;
  66.     my($max_height) = shift;
  67.     $fn = "$PWD/$fn" unless $fn=~ m:^/:;
  68.     my ($img);
  69.     $img = gimp_file_load(RUN_NONINTERACTIVE,$fn,$fn);
  70.     my ($w, $h) = ($img->width, $img->height);
  71.  
  72.     # Resize the img
  73.     if ($h > $max_height) {
  74.     my $scale = $max_height/$h;
  75.     my $new_w = int($w * $scale+0.5);
  76.     my $new_h = int($h * $scale+0.5);
  77. #    print "New w,h = ($new_w, $new_h)\n";
  78.     gimp_image_scale($img, $new_w, $new_h);
  79.     }
  80.  
  81.     return $img;
  82. }
  83.  
  84. ######################################################################
  85. #  hbox/vbox algorithm. This algorithm is much like a text flowing
  86. #  algorithm with centered paragraphs.
  87. ######################################################################
  88. sub hbox_vbox_add_row {
  89.     my($imgs, $layout_width, $row_start_idx, $row_end_idx, $ypos, $gutter_x) = @_;
  90.     my(@row_layout);
  91.  
  92.     # Calculate teh row width
  93.     my $row_width = 0;
  94.     my $row_height = 0;
  95.     for $i ($row_start_idx..$row_end_idx) {
  96.     my($w,$h) = ($imgs->[$i]->width, $imgs->[$i]->height);
  97.     $row_width += $gutter_x + $w;
  98.     $row_height = $h if $h > $row_height;
  99.     }
  100.     $row_width -= $gutter_x;
  101.  
  102.     # Do the layout
  103.     my $xpos = ($layout_width-$row_width)/2;
  104.     for $i ($row_start_idx..$row_end_idx) {
  105.     my $y = $ypos + ($row_height-$imgs->[$i]->height)/2;
  106.     push(@row_layout, [$imgs->[$i], $xpos, $y]);
  107.     $xpos+= $gutter_x + $imgs->[$i]->width;
  108.     }
  109.     return(@row_layout);
  110. }
  111.  
  112. sub hbox_vbox_create_layout {
  113.     my($imgs) = @_;
  114.     my(@layout);        # The positions of all the images
  115.  
  116.     # A simple maximal row algorithm
  117.     my ($row_start_idx, $row_end_idx);
  118.     my $ypos = $pad_y;
  119.     my $xpos = 0;
  120.     print "imsg->[0] = $imgs->[0]\n";
  121.     my $row_height = $imgs->[0]->height();
  122.     my $i;
  123.     foreach $img_idx (0..@$imgs-1) {
  124.     print "Layouting image #$img_idx\n";
  125.     my $w = $imgs->[$img_idx]->width();
  126.     my $h = $imgs->[$img_idx]->height();
  127.  
  128. #    print "row_width = $row_width\n";
  129.     # Check for the creation of a new row
  130.     if ($row_width + $pad_x * 2 + $w > $layout_width) {
  131.  
  132.         push(@layout,
  133.          hbox_vbox_add_row($imgs, $layout_width,
  134.                    $row_start_idx, $row_end_idx,
  135.                    $ypos, $gutter_x));
  136.         $total_width = $row_width if $row_width > $total_width;
  137.  
  138.         # Move to next row
  139.         $ypos+= $gutter_y + $row_height;
  140.  
  141.         # Zero out various things
  142.         $row_start_idx = $row_end_idx+1;
  143.         $row_end_idx = $row_start_idx;
  144.         $row_width = 0;
  145.         if ($row_start_idx < @imgs) {
  146.         $row_width = $imgs->[$row_start_idx]->width;
  147.         $row_height = $imgs->[$row_start_idx]->height;
  148.         $xpos = 0;
  149.         }
  150.     }
  151.     else {
  152.         $row_width += $gutter_x + $w;
  153.         $row_end_idx = $img_idx;
  154.         $row_height = $h if $h > $row_height;
  155.     }
  156.     }
  157.  
  158.     if ($row_start_idx < @imgs) {
  159.     push(@layout,
  160.          hbox_vbox_add_row($imgs, $layout_width,
  161.                    $row_start_idx, $row_end_idx,
  162.                    $ypos, $gutter_x));
  163.     $total_width = $row_width if $row_width > $total_width;
  164.  
  165.     $ypos+= $row_height;
  166.     }
  167.  
  168.     $total_width = $layout_width;
  169.     $total_height = $ypos + $pad_y;
  170.     return ($total_width, $total_height, \@layout);
  171. }
  172.  
  173. ######################################################################
  174. #  The decoration_drop_shadow creates one layer with the images
  175. #  and puts a drop shadow behind them.
  176. ######################################################################
  177. sub decoration_drop_shadow {
  178.     my($layout) = shift;
  179.     $shadow_xoffs = 7;
  180.     $shadow_yoffs = 7;
  181.  
  182.     # Put them on a row
  183.     $tiled_img = gimp_image_new($total_width, $total_height, RGB);
  184.     $tiled_drw = gimp_layer_new($tiled_img, $total_width, $total_height,
  185.                 RGB_IMAGE, "Tiled", 100, NORMAL_MODE);
  186.     $tiled_shadow = gimp_layer_new($tiled_img, $total_width, $total_height,
  187.                    RGB_IMAGE, "Shadow", 50, NORMAL_MODE);
  188.     $tiled_background = gimp_layer_new($tiled_img, $total_width, $total_height,
  189.                        RGB_IMAGE, "Background", 100, NORMAL_MODE);
  190.  
  191.     # Create masks
  192.     $tiled_drw_msk = $tiled_drw->create_mask(1);
  193.     $tiled_shadow_msk = $tiled_shadow->create_mask(1);
  194.  
  195.     # Make sure respective images have alpha channels
  196.     $tiled_drw->layer_add_alpha();
  197.     $tiled_shadow->layer_add_alpha();
  198.  
  199.     # Connect masks to respective layers
  200.     $tiled_img->add_layer_mask($tiled_drw, $tiled_drw_msk);
  201.     $tiled_img->add_layer_mask($tiled_shadow, $tiled_shadow_msk);
  202.  
  203.     # Fill all the layers with some contents
  204.     gimp_palette_set_background([128,128,128]);
  205.     $tiled_drw->fill(BG_IMAGE_FILL);
  206.  
  207.     gimp_palette_set_background($bgcolor);
  208.     $tiled_background->fill(BG_IMAGE_FILL);
  209.     if ($bgpattern) {
  210.     print "Setting pattern\n";
  211.     gimp_patterns_set_pattern($bgpattern);
  212.     $tiled_img->bucket_fill($tiled_background, PATTERN_BUCKET_FILL,
  213.                 NORMAL, 100, 0, FALSE, 0,0);
  214.     }
  215.     gimp_palette_set_background([0, 0, 0]);  # Shadow color
  216.     $tiled_shadow->fill(BG_IMAGE_FILL);
  217.  
  218.     # Add all the layers to the image
  219.     $tiled_img->add_layer($tiled_background,-1);
  220.     $tiled_img->add_layer($tiled_shadow,-1);
  221.     $tiled_img->add_layer($tiled_drw,-1);
  222.     gimp_display_new($tiled_img);
  223.  
  224.     my $xpos = 0;
  225.  
  226.     # Set color for drawing in mask
  227.     gimp_palette_set_background([255, 255, 255]);
  228.     for $ly_idx (0..@$layout-1) {
  229.     my ($img, $xpos, $ypos) = @{$layout->[$ly_idx]};
  230.     ($layer) = @{gimp_image_get_layers($img)};
  231.     my($w,$h) = ($img->width, $img->height);
  232.     $img->selection_all();
  233.     $img->edit_copy($layer);
  234.     $tiled_img->rect_select($xpos, $ypos, $w, $h, 0, 0, 0);
  235.     $tiled_img->edit_paste($tiled_drw, 0)
  236.         ->floating_sel_anchor;
  237.  
  238.     # why is the selection cleared?
  239.     $tiled_img->rect_select($xpos, $ypos, $w, $h, 0, 0, 0);
  240.     $tiled_img->edit_fill($tiled_drw_msk, BG_IMAGE_FILL);
  241.  
  242.     # why is the selection cleared?
  243.     $tiled_img->rect_select($xpos+$shadow_xoffs,
  244.                 $ypos+$shadow_yoffs, $w, $h, 0, 0, 0);
  245.     $tiled_img->edit_fill($tiled_shadow_msk, BG_IMAGE_FILL);
  246.  
  247.     $tiled_img->selection_none();
  248.  
  249.     }
  250.  
  251.     # Blur the shadow
  252.     plug_in_gauss_rle(1, $tiled_img, $tiled_shadow_msk, 7, 1, 1);
  253.  
  254.     # Apply the shadow mask
  255.     $tiled_img->remove_layer_mask($tiled_shadow, APPLY);
  256. }
  257.  
  258. sub decoration_sunken_windows {
  259.     my($layout) = shift;
  260.     $shadow_xoffs = 7;
  261.     $shadow_yoffs = 7;
  262.  
  263.     # Create needed image and layers
  264.     $tiled_img = gimp_image_new($total_width, $total_height, RGB);
  265.     $tiled_drw = gimp_layer_new($tiled_img, $total_width, $total_height,
  266.                 RGB_IMAGE, "Tiled", 100, NORMAL_MODE);
  267.     $tiled_punch_layer = gimp_layer_new($tiled_img, $total_width, $total_height,
  268.                 RGB_IMAGE, "Punched", 100, NORMAL_MODE);
  269.     $tiled_punch_stencil = gimp_layer_new($tiled_img, $total_width, $total_height,
  270.                 RGB_IMAGE, "Punch mask", 100, NORMAL_MODE);
  271.     # Create masks
  272.     $tiled_punch_mask = $tiled_punch_layer->create_mask(0);
  273.  
  274.     # Make sure respective images have alpha channels
  275.     $tiled_punch_layer->layer_add_alpha();
  276.  
  277.     # Connect masks to respective layers
  278.     $tiled_img->add_layer_mask($tiled_punch_layer, $tiled_punch_mask);
  279.  
  280.     # Fill all the layers with some contents
  281.     gimp_palette_set_background([128,128,128]);
  282.     $tiled_drw->fill(BG_IMAGE_FILL);
  283.  
  284.     gimp_palette_set_background($bgcolor);
  285.     $tiled_punch_layer->fill(BG_IMAGE_FILL);
  286.     if ($bgpattern) {
  287.     print "Setting pattern\n";
  288.     gimp_patterns_set_pattern($bgpattern);
  289.     $tiled_img->bucket_fill($tiled_punch_layer, PATTERN_BUCKET_FILL,
  290.                 NORMAL, 100, 0, FALSE, 0,0);
  291.     }
  292.     gimp_palette_set_background([255, 255, 255]);  # Punch stencil
  293.     $tiled_punch_stencil->fill(BG_IMAGE_FILL);
  294.  
  295.     # Add all the layers to the image
  296.     $tiled_img->add_layer($tiled_punch_stencil,-1);
  297.     $tiled_img->add_layer($tiled_drw,-1);
  298.     $tiled_img->add_layer($tiled_punch_layer,-1);
  299.     gimp_display_new($tiled_img);
  300.  
  301.     my $xpos = 0;
  302.  
  303.     # Set color for drawing in mask
  304.     gimp_palette_set_background([0, 0, 0]);
  305.     for $ly_idx (0..@$layout-1) {
  306.     my ($img, $xpos, $ypos) = @{$layout->[$ly_idx]};
  307.     ($layer) = @{gimp_image_get_layers($img)};
  308.     my($w,$h) = ($img->width, $img->height);
  309.     $img->selection_all();
  310.     $img->edit_copy($layer);
  311.     $tiled_img->rect_select($xpos, $ypos, $w, $h, 0, 0, 0);
  312.     $tiled_img->edit_paste($tiled_drw, 0)
  313.         ->floating_sel_anchor;
  314.  
  315.     # why is the selection cleared?
  316.     $bw = 3;
  317.     $tiled_img->rect_select($xpos-$bw,
  318.                 $ypos-$bw, $w+2*$bw, $h+2*$bw, 0, 0, 0);
  319.     $tiled_img->edit_fill($tiled_punch_stencil, BG_IMAGE_FILL);
  320.  
  321.     # why is the selection cleared?
  322.     $tiled_img->selection_none();
  323.     $tiled_img->rect_select($xpos, $ypos, $w, $h, 0, 0, 0);
  324.     $tiled_img->edit_fill($tiled_punch_mask, BG_IMAGE_FILL);
  325.  
  326.     $tiled_img->selection_none();
  327.     }
  328.  
  329.     # Blur the punch stencil
  330.     plug_in_gauss_rle(1, $tiled_img, $tiled_punch_stencil, 7, 1, 1);
  331.  
  332.     # Bump map
  333.     plug_in_bump_map(1, $tiled_img, $tiled_punch_layer, $tiled_punch_stencil,
  334.              135, 45, 4,0,0,0,0,1,0, SPHERICAL);
  335.  
  336.     # Apply the shadow mask
  337.     $tiled_img->remove_layer_mask($tiled_punch_layer, APPLY);
  338. }
  339.  
  340. sub delete_images {
  341.     my $imgs = shift;
  342.     foreach $img (@$imgs) {
  343.     $img->delete();
  344.     }
  345. }
  346.  
  347. ######################################################################
  348. #  Net is where main continues after it has connected to
  349. #  gimp.
  350. ######################################################################
  351. sub net {
  352.     open(IN, shift(@ARGV));
  353.  
  354.     # Read the file list
  355.     while(($fn,$descr) = get_next_record()) {
  356.     last unless $fn;
  357.     next unless -e $fn;
  358.     print "fn = $fn\n";
  359.     push(@imgs, load_img($fn, $max_height));
  360.     push(@filenames, $fn);
  361.     }
  362.  
  363.     print "Done reading ", scalar(@imgs), " images\n";
  364.  
  365.     # Now create a layout of the images. The layout algorithm
  366.     # should really be parameterized.
  367.     my ($total_width, $total_height, $layout) = hbox_vbox_create_layout(\@imgs);
  368.  
  369.     print "total_size = ($total_width $total_height)\n";
  370.  
  371.     # This is an example decoration. Others will be created in the future
  372.     if ($decoration eq "drop-shadow") {
  373.     decoration_drop_shadow($layout);
  374.     } elsif ($decoration eq "sunken-windows") {
  375.     decoration_sunken_windows($layout);
  376.     } else {
  377.     delete_images(\@imgs);
  378.     die "Unknown decoration $decoration!\n";
  379.     }
  380.  
  381.     $tiled_img->flatten() if $do_flatten;
  382.     gimp_displays_flush();
  383.  
  384.     # Now create the index file
  385.     if ($index_file) {
  386.     open(INDEX, ">$index_file");
  387.     for $idx (0..@filenames-1) {
  388.         my ($img, $xpos, $ypos) = @{$layout->[$idx]};
  389.         my($w,$h) = ($img->width, $img->height);
  390.  
  391.         printf INDEX "%s %.0f %.0f %.0f %.0f %s\n",
  392.             $filenames[$idx], $xpos, $ypos, $xpos+$w, $ypos+$h, $descr;
  393.     }
  394.     close(INDEX);
  395.     }
  396.  
  397.     # Clean up
  398.     delete_images(\@imgs);
  399. }
  400.  
  401. # Parse command line arguments
  402. while($_ = $ARGV[0], /^-/) {
  403.     shift;
  404.     /^-help/ and do { print <<__; exit; };
  405. make-img-map - Make an image map from a list of images
  406.  
  407. Syntax:
  408.     gimp-make-img-map [-max_height mh] [-htmlindex hi] [-layoutwidth lw]
  409.              [-flatten] [-bgcolor clr] [-bgpattern ptn] list
  410.  
  411. Description:
  412.     gimp-make-img-map communicates with Gimp through the Perl Net-Server
  413.     and automizes the process of combining a list of images into an
  414.     image map for use e.g. within a HTML page.
  415.  
  416. Options:
  417.     -max_height mh   Set max height of images. (Default $max_height)
  418.     -index if        Create an index file mapping filename to bounding box
  419.                  coordinates in output image, where if is the name of
  420.              the index file. The index file may e.g. be translated by
  421.              a subsequent program into a html index file.
  422.     -layoutwidth lw  Set total width of layout. (Default $layout_width)
  423.     -flatten         Flatten the final image.
  424.     -bgcolor         Set bg color.
  425.     -bgpattern       Set bg pattern. Overrides the bgcolor.
  426.     -padx px         Extra space around all images in x-direction. (Default $pad_x)
  427.     -pady py         Extra space around all images in y-direction. (Default $pad_y)
  428.     -gutterx gx      Space between images in x-direction. (Default $gutter_x)
  429.     -gutterx gy      Space between images in y-direction. (Default $gutter_y)
  430.     -decoration alg  Choose algorithm for drawing the decoration in the layout.
  431.              Known algorithms are:
  432.                drop-shadow
  433.                sunken-windows
  434.              Default is 'drop_shadow'.
  435. __
  436.  
  437.     /^-max_height/  and do { $max_height = shift; next; };
  438.     /^-index/       and do { $index_file = shift; next; };
  439.     /^-layoutwidth/ and do { $layout_width = shift; next; };
  440.     /^-flatten/     and do { $do_flatten++; next; };
  441.     /^-bgcolor/     and do { $background = shift; next; };
  442.     /^-bgpattern/   and do { $bgpattern = shift; next; };
  443.     /^-decoration/  and do { $decoration = shift; next; };
  444.     /^-gutterx/        and do { $gutter_x = shift; next; };
  445.     /^-guttery/        and do { $gutter_y = shift; next; };
  446.     /^-padx/        and do { $pad_x = shift; next; };
  447.     /^-pady/        and do { $pad_x = shift; next; };
  448.     die "Unknown option $_!\n";
  449. }
  450.  
  451. # Translate background into a color according to the X11 color dbase.
  452. exit main;
  453.